package asruby.runtime
{
import asruby.Ruby;
import asruby.exceptions.RaiseException;
import asruby.lang.RubyException;
import asruby.lang.RubyProc;
import asruby.lang.RubyWarnings;

import flash.utils.Dictionary;
	
public class GlobalVariables
{
  	private var runtime: Ruby;
    private var globalVariables: Dictionary = new Dictionary();

    public function  GlobalVariables(runtime: Ruby) {
        this.runtime = runtime;
    }

    public function  define(name: String, value: IRubyObject): void {
        globalVariables[name] = value;
    }
    
    public function  defineReadonly(name: String, value: IRubyObject): void {
		/*         assert name != null;
        assert accessor != null;
        assert name.startsWith("$"); */

        globalVariables[name] = value; //new GlobalVariable(name);
    }

    public function  isDefined(name: String): Boolean {
        /* assert name != null;
        assert name.startsWith("$"); */
        
        var variable:Object = globalVariables[name];
        return variable != null; // && !(variable.getAccessor() instanceof UndefinedAccessor);
    }

    /** Creates a new global variable which links to
     * the oldName global variable.
     * 
     * <b>WANRING</b> we are already using the 1.7.1 behaviour.
     */
    public function  alias(name: String, oldName: String): void {
        var oldVariable: IRubyObject = createIfNotDefined(oldName, null);
        var variable:GlobalVariable = globalVariables[name];

        if (variable != null && oldVariable != variable && variable.isTracing()) {
            throw new RaiseException(null, false);
        }

        globalVariables.put(name, oldVariable);
    }

    public function  getVal(name: String): IRubyObject {
	    /* assert name != null;
	    assert name.startsWith("$"); */
	
	    var variable:IRubyObject = globalVariables[name];
	    if (variable != null) {
	        return globalVariables[name];
	    }
		runtime.getWarnings().warning(RubyWarnings.GLOBAL_NOT_INITIALIZED, "global variable `" + name + "' not initialized", name);
		return runtime.getNil();
	}

    public function  setVal(name: String, value: IRubyObject): IRubyObject {
       /*  assert name != null;
        assert name.startsWith("$"); */

/*         if (runtime.getSafeLevel() >= 4) {
            throw runtime.newSecurityError("Insecure: can't change global variable value");
        } */

        return createIfNotDefined(name, value);
/*         var result: IRubyObject = variable.getAccessor().setValue(value);
        variable.trace(value); */
        //return result;
    }
    
    public function  setTraceVar(name: String, proc: RubyProc): void {
        /* assert name != null;
        assert name.startsWith("$"); */
        
        var variable: IRubyObject = createIfNotDefined(name, null);
        //variable.addTrace(proc);
    }
    
    public function  untraceVar(name: String, command: IRubyObject): Boolean {
        /* assert name != null;
        assert name.startsWith("$");
         */
        if (isDefined(name)) {
            var variable:GlobalVariable = globalVariables[name];
            return variable.removeTrace(command);
        }
        return false;
    }
    
    public function  untraceVar2(name: String): void {
       /*  assert name != null;
        assert name.startsWith("$");
         */
        if (isDefined(name)) {
            var variable:GlobalVariable = globalVariables[name];
            variable.removeTraces();
        }
    }

    public function  getNames(): Array {
        return globalVariables.keySet();
    }

    private function  createIfNotDefined(name: String, value:IRubyObject): IRubyObject {
        var existingVal:IRubyObject = globalVariables[name];
        if (existingVal == null) {
            //var variable:GlobalVariable  = GlobalVariable.newUndefined(runtime, name);
            existingVal = value;
            globalVariables[name] = existingVal;
        }
        return existingVal;
    }

/*     private var defaultSeparator: IRubyObject;

    public function  getDefaultSeparator(): IRubyObject {
        return defaultSeparator;
    }

    public function  setDefaultSeparator(defaultSeparator: IRubyObject): void {
        this.defaultSeparator = defaultSeparator;
    } */
}
}